package com.navinfo.platform.trip.common.arithmetic;

import com.navinfo.platform.trip.common.arithmetic.data.CommonData;
import com.navinfo.platform.trip.common.arithmetic.data.OuterStatisticData;
import com.navinfo.platform.trip.common.arithmetic.var.VarVehicleEstimatedLoad;
import com.navinfo.platform.trip.common.arithmetic.enums.LoadTypeEnum;
import com.navinfo.platform.trip.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.platform.trip.common.config.ConfigMap;
import com.navinfo.platform.trip.common.vehicle.VehicleInfo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 载荷算法<br/>
 * 依赖{@link VehicleInfo}的发动机输出最大扭距、满半空阀值<br/>
 * 输出：统计<br/>
 */
public class VehicleEstimatedLoad extends AbstractArithmetic<VarVehicleEstimatedLoad> {
    /**
     * 扭矩阈值
     */
    private Integer engineOutputTorqueThreshold = ConfigMap.getInteger("EngineOutputTorque_Threshold");
    /**
     * 速度阈值
     */
    private Integer speed = ConfigMap.getInteger("VehicleEstimatedLoad_Speed");
    /**
     * 扭矩系数
     */
    private Double torqueCoefficient = 0.0;

    /**
     * 默认Power
     */
    private Double power = ConfigMap.getDouble("VehicleEstimatedLoad_Power");
    /**
     * 默认系数
     */
    private Double coefficient = ConfigMap.getDouble("VehicleEstimatedLoad_Default_Threshold");
    /**
     * 载重最小值
     */
    private Double massAgvMin = ConfigMap.getDouble("VehicleEstimatedLoad_MassAgv_Min");
    /**
     * 载重最大值
     */
    private Double massAgvMax = ConfigMap.getDouble("VehicleEstimatedLoad_MassAgv_Max");
    /**
     * 超出额定载重 指定件数后视为可纠偏载重
     */
    private Integer cntMin = ConfigMap.getInteger("VehicleEstimatedLoad_Cnt_Min");
    /**
     * 载重 最后N件取平均值 视为最终有效载重
     */
    private Integer lastCnt = ConfigMap.getInteger("VehicleEstimatedLoad_Cnt_Last");

    @Override
    public void calculate() {
        logger.debug("===============载荷算法开始===========");
        CommonData commonData = drivingData.getCommonData();
        VehicleInfo vehicleInfo = drivingData.getVehicleInfo();
        if (vehicleInfo == null) {
            logger.debug("载荷算法：获取车辆信息为空，无法计算");
            return;
        }

        //扭矩系数
        torqueCoefficient = vehicleInfo.getEngineMaxTorque()/100;
        if (torqueCoefficient < 1) {
            logger.debug("载荷算法：车辆最大扭矩有误{}，无法计算", vehicleInfo.getEngineMaxTorque());
            return;
        }

        int brake = commonData.isBrake() ? 1 : 0;
        int speedKmh = commonData.getSpeedKmh();
        int rotation = commonData.getRotation();

        //内耗百分比
        int loss = 0;
        if(rotation >=700 && rotation < 1000){
            loss = 1;
        }else if(rotation >=1000 && rotation < 1500){
            loss = 3;
        }else if(rotation >=1500 && rotation < 2000){
            loss = 5;
        }else if(rotation > 2000){
            loss = 6;
        }

        //计算当前点扭矩，还应考虑发动机内耗，（扭矩百分比-内耗百分比）（内耗百分比：700rmp~1000rmp 1%  1000~1500 3%  1500~2000 5%)。(0.92,0.97是摩擦等损耗)
        double engineOutputTorque = (commonData.getEngineOutputTorque() - loss) * torqueCoefficient * 0.92 * 0.97;
        if (engineOutputTorque < 0) {
            engineOutputTorque = 0;
        }

        //当前点加速度
        double acceleratedSpeed = commonData.getAcceleration();
        VarVehicleEstimatedLoad var = super.getObj();
        if (!commonData.isTripFirstNode()) {
            double preEngineOutputTorque = var.getPreEngineOutputTorque();
            double abs = Math.abs(engineOutputTorque - preEngineOutputTorque);
            double spdRatio = var.getSpdRatio();
            double speedRatioAbs = Math.abs((speedKmh > 0 ? rotation / 1.0 / speedKmh : 0) - spdRatio);

            if (abs>engineOutputTorqueThreshold && speedRatioAbs<0.5 && brake==0 && var.getPreBrake()==0 && speedKmh>speed && commonData.getAcceleratorPosition()>10 && commonData.getEngineOutputTorque()>10 && commonData.getFuelConsumptionRate().doubleValue() > 0) {
                logger.debug("engineOutputTorque={}n·m,rotation={}rpm,preEngineOutputTorque={}n·m,preRotation={}rpm",engineOutputTorque, rotation, preEngineOutputTorque, var.getPreRotation());
                double tempA = ((engineOutputTorque*rotation - preEngineOutputTorque*var.getPreRotation()) * 120 * 3.14) / 1000;
                logger.debug("tempA=((engineOutputTorque * rotation - preEngineOutputTorque * var.getPreRotation()) * 120 * Math.PI ) / 1000={}",tempA);

                double prePower = var.getPrePower();
                double tempB = BigDecimal.valueOf(prePower * tempA).divide(BigDecimal.valueOf(1 + tempA * tempA * prePower), 20, BigDecimal.ROUND_HALF_UP).doubleValue();
                logger.debug("prePower={},tempA={},tempB=prePower*tempA/(1+tempA*tempA*prePower)={}", prePower, tempA, tempB);
                double curPower = (1 - tempA * tempB) * prePower;
                logger.debug("curPower=(1 - tempA * tempB) * prePower={}", curPower);
                if (curPower == 0.0) {
                    curPower = power;
                }
                var.setPrePower(curPower);

                double accData = var.getAccData();
                double accDelta = accData * acceleratedSpeed * speedKmh - accData * var.getPreAcceleratedSpeed() * var.getPreSpeedKmh();
                double preTheta = var.getPreTheta();
                double theta = preTheta + tempB * (accDelta - tempA * preTheta);
                logger.debug("preTheta={},tempA={},accDelta={},theta=(preTheta + tempB * (accDelta - tempA * preTheta))={}", tempA, accDelta, theta);

                //原始载荷
                double massAgv = 0d;
                if (!Double.isNaN(theta) && Double.isFinite(theta)) {
                    if (theta != 0.0 && theta > 0) {
                        massAgv = BigDecimal.valueOf(1).divide(BigDecimal.valueOf(theta), 20, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                } else {
                    var.setPreTheta(0d);
                }

                logger.debug("原始载荷:{}", massAgv);

                //根据最大扭矩调整范围
                if (torqueCoefficient < 14) {
                    massAgvMin = 6000.0;
                    massAgvMax = 50000.0;
                } else if (torqueCoefficient >= 14 && torqueCoefficient <= 20) {
                    massAgvMin = 8000.0;
                    massAgvMax = 70000.0;
                } else {
                    massAgvMin = 8000.0;
                    massAgvMax = 90000.0;
                }

                // ==================== 纠偏 开始 =====================
                // 额定载重(单位：0.1吨)
                Integer fullWload = vehicleInfo.getWloadFull();
                if(fullWload!=null && fullWload > 0){
                    // 单位变换 0.1吨-> KG
                    fullWload = fullWload * 100;
                    // 计算纠偏 如果超出额定载重 +10吨，则使用额定载重
                    if(massAgv > fullWload + 10000){
                        logger.debug(" =======>>>> 超出额定载重 +10吨:{}", massAgv);
//                        Integer overWloadCnt = overLoad.get(terminalId);
                        Integer overWloadCnt = var.getOverLoad();
                        if(overWloadCnt == null) overWloadCnt = 0;
                        if(overWloadCnt < cntMin){
//                            overLoad.put(terminalId, overWloadCnt + 1);
                            var.setOverLoad(overWloadCnt + 1);
                            logger.debug(" =======>>>> 超出额定载重 件数:{}", overWloadCnt + 1);
                            return;
                        } else {
                            logger.debug(" =======>>>> 计算纠偏:计算值:{},使用额定载重:{}", massAgv, fullWload);
                            massAgv = fullWload + 10000;
                        }
                    }
                } else {
//                    overLoad.put(terminalId, 0);
                    var.setOverLoad(0);
                }
                // ==================== 纠偏 结束 =====================

                if ((massAgv > massAgvMin) && (massAgv < massAgvMax)) {
                    var.setPreTheta(theta);
                    double lastEst = var.getVehicleEstimatedLoad();
                    double vehicleEstimatedLoad = massAgv;
                    if (lastEst > 0) {
                        vehicleEstimatedLoad = coefficient * massAgv + (1 - coefficient) * lastEst;
                    }
                    List<Double> list = var.getLastEsts();
                    if(list == null){
                        list = new ArrayList<>();
                    }
                    if (list.size() == lastCnt && Math.abs(vehicleEstimatedLoad - list.get(0)) < 2000) {
                        var.setEstCount(var.getEstCount() + 1);
                        var.setEstSum(var.getEstSum() + vehicleEstimatedLoad);
                        if(var.getEstSum()/var.getEstCount() < 18000){
                            var.setAccData(1.3);
                        }else{
                            var.setAccData(1);
                        }
                        logger.debug("滤波后载荷:{}", vehicleEstimatedLoad);
                    }
                    var.setVehicleEstimatedLoad(vehicleEstimatedLoad);

                    list.add(vehicleEstimatedLoad);
                    if (list.size() > lastCnt) {
                        list.remove(0);
                    }
                    var.setLastEsts(list);
                }
            }
        } else {
            var.setPrePower(power);
        }
        if (speedKmh > 0) {
            var.setSpdRatio(rotation / 1.0 / speedKmh);
        } else {
            var.setSpdRatio(0);
        }

        var.setPreAcceleratedSpeed(acceleratedSpeed);
        var.setPreEngineOutputTorque(engineOutputTorque);
        var.setPreBrake(brake);
        var.setPreSpeedKmh(speedKmh);
        var.setPreRotation(rotation);

        logger.debug("===============载荷算法结束===========");
    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarVehicleEstimatedLoad var = getObj();
        logger.debug("载荷算法的统计结果{}", var);
        int vehicleEstimatedLoad = 0;
//        if(var.getEstCount() > 0 ) {
//            vehicleEstimatedLoad = BigDecimal.valueOf(var.getEstSum() / var.getEstCount()).
//                    divide(BigDecimal.valueOf(100), 0, BigDecimal.ROUND_HALF_UP).intValue();
//        }
        List<Double> list = var.getLastEsts();
        if(null != list){
            int size = list.size();
            if(size > 0){
//            int endIndex = size - 1;
                List<Double> latestList;
                if(size >= lastCnt){
                    latestList = list.subList(size - lastCnt , size - 1);
                    double load = latestList.parallelStream().mapToDouble(x -> x).sum();
                    vehicleEstimatedLoad = BigDecimal.valueOf(load / lastCnt).divide(BigDecimal.valueOf(100), 0, BigDecimal.ROUND_HALF_UP).intValue() ;
                }
            }
        }

        statisticDataOut.setVehicleEstimatedLoad(vehicleEstimatedLoad);

        //满半空判断
        VehicleInfo vehicleInfo = drivingData.getVehicleInfo();
        LoadTypeEnum loadTypeEnum = LoadTypeEnum.UNDEF;
        if(vehicleInfo!=null && vehicleInfo.getWloadFull()!=null && vehicleInfo.getWloadEmpty()!=null && vehicleInfo.getWloadHalf()!=null){
            int empty = vehicleInfo.getWloadEmpty();
            int half = vehicleInfo.getWloadHalf();
            int full = vehicleInfo.getWloadFull();
            int load = statisticDataOut.getVehicleEstimatedLoad();
            if(load>0) {
                if (load <= empty) {
                    loadTypeEnum = LoadTypeEnum.EMPTY;
                } else if (load <= half) {
                    loadTypeEnum = LoadTypeEnum.HALF;
                } else if (load <= full) {
                    loadTypeEnum = LoadTypeEnum.FULL;
                } else {
                    loadTypeEnum = LoadTypeEnum.OVER;
                }
            }
        }
        statisticDataOut.setWloadType(loadTypeEnum.getValue());
    }

}
